import backtrader as bt
import logging
import json
from datetime import datetime
from .DbOprate import DbOprate
from .TDXFunctions import TDXFunctions
from .FactorDataManager import FactorDataManager

class TDXGPJYStrategy(bt.Strategy):
    """
    通达信GPJY策略（优化版本 - 使用因子数据缓存）
    """
    params = (
        ('d1', 20),      # 20日周期
        ('d2', 10),      # 10日周期 - 过滤周期
        ('g1', 40),      # 40日周期
        ('g2', 20),      # 20日周期 - 过滤周期
    )
    
    def __init__(self):
        self.data_close = self.datas[0].close
        self.data_low = self.datas[0].low
        self.data_high = self.datas[0].high
        self.tdx = TDXFunctions()
        
        # 初始化因子数据管理器
        self.stock_code = self.datas[0]._name
        self.factor_manager = FactorDataManager(self.stock_code)
        
        # 确保Redis连接正常
        try:
            self.factor_manager.redis_client.ping()
            print("Redis连接成功")
        except:
            print("Redis连接失败，将只使用数据库存储")
        
        # 在初始化时加载因子数据到Redis
        loaded_count = self.factor_manager.load_factors_to_redis()
        print(f"初始化完成，加载了 {loaded_count} 条因子数据")

        # 存储历史数据（用于计算需要历史数据的因子）
        self.history_data = {
            'close': [],
            'low': [],
            'high': [],
            'x_13': [],
            'x_13_1': [],
            'x_13_2': [],
            'x_14': [],
            'ddd1': [],
            'newb': [],
            'newnumber': [],
            'p3': [],
            'x_7': [],
            'x_8': [],
            'x_9': [],
            'hl': [],
            'll': [],
            'x_10': [],
            'x_10_1': [],
            'x_10_2': [],
            'x_11': [],
            'gd': [],
            'zhangting': [],
            'c1': []
        }

        # 设置日志
        self.setup_logging()

    def setup_logging(self):
        """设置日志配置"""
        self.logger = logging.getLogger(f'TDXGPJYStrategy_{self.stock_code}')
        self.logger.setLevel(logging.INFO)
        
        # 创建文件处理器
        log_filename = f'tdx_gpjy_strategy_{self.stock_code}_{datetime.now().strftime("%Y%m%d")}.log'
        file_handler = logging.FileHandler(log_filename, encoding='utf-8')
        file_handler.setLevel(logging.INFO)
        
        # 创建格式器
        formatter = logging.Formatter('%(asctime)s - %(message)s')
        file_handler.setFormatter(formatter)
        
        # 添加处理器
        if not self.logger.handlers:
            self.logger.addHandler(file_handler)

    def log_daily_params(self, params_dict):
        """记录每日参数到日志文件"""
        log_msg = "\n" + "="*100 + "\n"
        log_msg += f"日期: {params_dict['date']}\n"
        log_msg += f"股票代码: {self.stock_code}\n"
        log_msg += "-"*100 + "\n"
        log_msg += f"CLOSE: {params_dict['close']:.4f}\n"
        log_msg += f"LOW: {params_dict['low']:.4f}\n"
        log_msg += f"HIGH: {params_dict['high']:.4f}\n"
        log_msg += f"X_13: {params_dict['x_13']}\n"
        log_msg += f"X_14: {params_dict['x_14']}\n"
        log_msg += f"DDD1: {params_dict['ddd1']:.4f}\n"
        log_msg += f"NEWB: {params_dict['newb']}\n"
        log_msg += f"NEWNUMBER: {params_dict['newnumber']}\n"
        log_msg += f"P3: {params_dict['p3']:.4f}\n"
        log_msg += f"X_7: {params_dict['x_7']:.4f}\n"
        log_msg += f"X_8: {params_dict['x_8']:.4f}\n"
        log_msg += f"X_9: {params_dict['x_9']:.4f}\n"
        log_msg += f"HL: {params_dict['hl']}\n"
        log_msg += f"LL: {params_dict['ll']}\n"
        log_msg += f"X_10: {params_dict['x_10']}\n"
        log_msg += f"X_11: {params_dict['x_11']}\n"
        log_msg += f"GD: {params_dict['gd']:.4f}\n"
        log_msg += f"基础B: {params_dict['jichub']}\n"
        log_msg += f"基础S: {params_dict['jichus']}\n"
        log_msg += "="*100 + "\n"
        
        self.logger.info(log_msg)

    def save_signal_to_database(self, signal_type, current_date, current_price, additional_info=None):
        """保存信号到数据库"""
        try:
            result = {
                'strategy': 'TDXGPJYStrategy_'+signal_type,
                'stock_code': self.stock_code,
                'op_act': signal_type,
                'op_price': float(current_price),
                'op_num': 100,
                'op_comm': 0.0,
                'op_dt': current_date.isoformat(),
                'reason': f'{signal_type.capitalize()}信号触发',
                'detail_info': additional_info or f'价格: {current_price:.4f}'
            }
            DbOprate.save_result_to_mysql_all(result)
            self.logger.info(f"信号已存入数据库: {signal_type} - 日期={current_date}, 价格={current_price:.4f}")
            print(f'{current_date} - *** {signal_type.capitalize()}信号已存入数据库 *** 价格: {current_price:.4f}')
        except Exception as e:
            self.logger.error(f"数据库存储失败: {str(e)}")
            print(f'{current_date} - *** 数据库存储失败: {str(e)} ***')

    def save_factor_data(self, trade_date, factor_key, factor_val):
        """保存因子数据到数据库和Redis"""
        try:
            # 保存到数据库
            self.factor_manager.save_factor_to_db(trade_date, factor_key, factor_val)
            # 保存到Redis
            self.factor_manager.save_factor_to_redis(trade_date, factor_key, factor_val)
        except Exception as e:
            print(f"保存因子数据失败: {e}")

    def get_factor_data(self, trade_date, factor_key):
        """获取因子数据（优先从Redis获取，没有则返回None）"""
        return self.factor_manager.get_factor_from_redis(trade_date, factor_key)

    def calculate_triple_sma(self, data, period=2, weight=1):
        """
        计算三层SMA: SMA(SMA(SMA(data,2,1),2,1),2,1)
        """
        if len(data) < 3:
            return data[-1] if len(data) > 0 else 0
        
        # 第一层SMA
        sma1_result = self.tdx.SMA(data, period, weight)
        if len(sma1_result) == 0:
            return data[-1] if len(data) > 0 else 0
            
        # 第二层SMA
        sma2_result = self.tdx.SMA(sma1_result, period, weight)
        if len(sma2_result) == 0:
            return sma1_result[-1] if len(sma1_result) > 0 else 0
            
        # 第三层SMA
        sma3_result = self.tdx.SMA(sma2_result, period, weight)
        if len(sma3_result) == 0:
            return sma2_result[-1] if len(sma2_result) > 0 else 0
            
        return sma3_result[-1]

    def next(self):
        current_date = self.datas[0].datetime.date(0)
        current_price = float(self.data_close[0])
        current_low = float(self.data_low[0])
        current_high = float(self.data_high[0])
        trade_date_int = int(current_date.strftime('%Y%m%d'))

        # 先尝试从Redis获取已计算的因子值
        cached_x_13 = self.get_factor_data(trade_date_int, 'X_13')
        cached_x_14 = self.get_factor_data(trade_date_int, 'X_14')
        cached_ddd1 = self.get_factor_data(trade_date_int, 'DDD1')
        cached_newb = self.get_factor_data(trade_date_int, 'NEWB')
        cached_newnumber = self.get_factor_data(trade_date_int, 'NEWNUMBER')
        cached_p3 = self.get_factor_data(trade_date_int, 'P3')
        cached_x_7 = self.get_factor_data(trade_date_int, 'X_7')
        cached_x_8 = self.get_factor_data(trade_date_int, 'X_8')
        cached_x_9 = self.get_factor_data(trade_date_int, 'X_9')
        cached_hl = self.get_factor_data(trade_date_int, 'HL')
        cached_ll = self.get_factor_data(trade_date_int, 'LL')
        cached_x_10 = self.get_factor_data(trade_date_int, 'X_10')
        cached_x_11 = self.get_factor_data(trade_date_int, 'X_11')
        cached_gd = self.get_factor_data(trade_date_int, 'GD')

        # 如果有缓存数据，使用缓存
        use_cache = (cached_x_13 is not None and cached_x_13 != '') and (cached_x_8 is not None and cached_x_8 != '')
        if use_cache:
            # 使用缓存数据
            x_13_numeric = int(cached_x_13)
            x_14_value = int(cached_x_14)
            ddd1_value = float(cached_ddd1)
            newb_value = bool(int(cached_newb))
            newnumber_value = int(cached_newnumber)
            p3_value = float(cached_p3)
            x_7_value = float(cached_x_7)
            x_8_value = float(cached_x_8)
            x_9_value = float(cached_x_9)
            hl_value = bool(int(cached_hl))
            ll_value = bool(int(cached_ll))
            x_10_numeric = int(cached_x_10)
            x_11_value = int(cached_x_11)
            gd_value = float(cached_gd)
            
            print(f"{current_date} - 使用缓存因子数据")
        else:
            # 没有缓存，需要重新计算
            print(f"{current_date} - 计算因子数据...cached_x_13:{cached_x_13},cached_x_8:{cached_x_8}")
            
            # 更新历史数据
            self.history_data['close'].append(current_price)
            self.history_data['low'].append(current_low)
            self.history_data['high'].append(current_high)
            
            # X_13:=CLOSE=LLV(CLOSE,D1);{是否20日最低收盘价}
            llv_value = self.tdx.LLV(self.data_close, self.p.d1)
            x_13_value = abs(current_price - llv_value) < 0.0001
            x_13_numeric = int(x_13_value)
            self.history_data['x_13'].append(x_13_numeric)
            
            # X_14:=BARSLAST(FILTER(CROSS(0.8,X_13),D2))+1;
            x_13_1_value = False
            if len(self.history_data['x_13']) >= 2:
                x_13_prev = self.history_data['x_13'][-2]
                x_13_curr = self.history_data['x_13'][-1]
                x_13_1_value = self.tdx.CROSS_simple(0.8, 0.8, x_13_prev, x_13_curr)
            self.history_data['x_13_1'].append(x_13_1_value)
            
            x_13_2_value = False
            if len(self.history_data['x_13_1']) > 0:
                all_filtered = self.tdx.FILTER(self.history_data['x_13_1'], self.p.d2)
                x_13_2_value = all_filtered[-1] if len(all_filtered) > 0 else False
            self.history_data['x_13_2'].append(x_13_2_value)
            
            barslast_value = self.tdx.BARSLAST(self.history_data['x_13_2'])
            x_14_value = barslast_value + 1
            self.history_data['x_14'].append(x_14_value)
            
            # DDD1:=REF(LOW,X_14);
            ddd1_value = self.tdx.REF(self.data_low, x_14_value)
            self.history_data['ddd1'].append(ddd1_value)
            
            # NEWB:=IF(DDD1!=REF(DDD1,1),1,0);
            newb_value = False
            if len(self.history_data['ddd1']) >= 2:
                ddd1_prev = self.history_data['ddd1'][-2]
                ddd1_curr = self.history_data['ddd1'][-1]
                newb_value = abs(ddd1_curr - ddd1_prev) > 0.0001
            self.history_data['newb'].append(newb_value)
            
            # NEWNUMBER:=BARSLAST(NEWB);
            newnumber_value = self.tdx.BARSLAST(self.history_data['newb'])
            self.history_data['newnumber'].append(newnumber_value)
            
            # P3:=EMA(CLOSE,43);
            p3_value = self.tdx.EMA(self.data_close, 43)
            self.history_data['p3'].append(p3_value)
            
            # X_7:=MA(CLOSE,1);
            x_7_value = current_price  # MA(CLOSE,1)就是当前收盘价
            self.history_data['x_7'].append(x_7_value)
            
            # X_8:=SMA(SMA(SMA(X_7,2,1),2,1),2,1);
            x_8_value = self.calculate_triple_sma(self.history_data['x_7'], 2, 1)
            self.history_data['x_8'].append(x_8_value)
            
            # X_9:=MA(X_8,3);
            if len(self.history_data['x_8']) >= 3:
                x_9_sum = sum(self.history_data['x_8'][-3:])
                x_9_value = x_9_sum / 3
            else:
                x_9_value = x_8_value
            self.history_data['x_9'].append(x_9_value)
            
            # HL := X_8 >= X_9;
            hl_value = x_8_value >= x_9_value
            self.history_data['hl'].append(hl_value)
            
            # LL := X_8 <= X_9;
            ll_value = x_8_value <= x_9_value
            self.history_data['ll'].append(ll_value)
            
            # X_10:=CLOSE=HHV(CLOSE,G1);{收盘价是否40日最高收盘价}
            hhv_value = self.tdx.HHV(self.data_close, self.p.g1)
            x_10_value = abs(current_price - hhv_value) < 0.0001
            x_10_numeric = int(x_10_value)
            self.history_data['x_10'].append(x_10_numeric)
            
            # X_11:=BARSLAST(FILTER(CROSS(0.8,X_10),G2))+1;
            x_10_1_value = False
            if len(self.history_data['x_10']) >= 2:
                x_10_prev = self.history_data['x_10'][-2]
                x_10_curr = self.history_data['x_10'][-1]
                x_10_1_value = self.tdx.CROSS_simple(0.8, 0.8, x_10_prev, x_10_curr)
            self.history_data['x_10_1'].append(x_10_1_value)
            
            x_10_2_value = False
            if len(self.history_data['x_10_1']) > 0:
                all_filtered = self.tdx.FILTER(self.history_data['x_10_1'], self.p.g2)
                x_10_2_value = all_filtered[-1] if len(all_filtered) > 0 else False
            self.history_data['x_10_2'].append(x_10_2_value)
            
            barslast_x11_value = self.tdx.BARSLAST(self.history_data['x_10_2'])
            x_11_value = barslast_x11_value + 1
            self.history_data['x_11'].append(x_11_value)
            
            # GD:=REF(HIGH,X_11);{短期高点开始画虚线}
            gd_value = self.tdx.REF(self.data_high, x_11_value)
            self.history_data['gd'].append(gd_value)
            
            # 保存计算结果到数据库和Redis
            self.save_factor_data(trade_date_int, 'X_13', x_13_numeric)
            self.save_factor_data(trade_date_int, 'X_14', x_14_value)
            self.save_factor_data(trade_date_int, 'DDD1', ddd1_value)
            self.save_factor_data(trade_date_int, 'NEWB', int(newb_value))
            self.save_factor_data(trade_date_int, 'NEWNUMBER', newnumber_value)
            self.save_factor_data(trade_date_int, 'P3', p3_value)
            self.save_factor_data(trade_date_int, 'X_7', x_7_value)
            self.save_factor_data(trade_date_int, 'X_8', x_8_value)
            self.save_factor_data(trade_date_int, 'X_9', x_9_value)
            self.save_factor_data(trade_date_int, 'HL', int(hl_value))
            self.save_factor_data(trade_date_int, 'LL', int(ll_value))
            self.save_factor_data(trade_date_int, 'X_10', x_10_numeric)
            self.save_factor_data(trade_date_int, 'X_11', x_11_value)
            self.save_factor_data(trade_date_int, 'GD', gd_value)

        # ========== 信号计算 ==========
        
        # 涨停:=(C-REF(C,1))/REF(C,1)>0.094;
        zhangting_value = False
        if len(self.data_close) >= 2:
            prev_close = float(self.data_close[-1])
            if prev_close != 0:
                zhangting_value = (current_price - prev_close) / prev_close > 0.094
        self.history_data['zhangting'].append(zhangting_value)
        
        # C1:=COUNT(涨停, 20) >= 1;{20天至少一次涨停}
        c1_value = False
        if len(self.history_data['zhangting']) >= 20:
            count_zt = sum(self.history_data['zhangting'][-20:])
            c1_value = count_zt >= 1
        elif len(self.history_data['zhangting']) > 0:
            count_zt = sum(self.history_data['zhangting'])
            c1_value = count_zt >= 1
        self.history_data['c1'].append(c1_value)
        
        # 基础B: CROSS(C,X_9) AND NEWNUMBER<9 AND C>P3 AND C1;
        jichub_value = False
        cross_c_x9 = False
        if len(self.data_close) >= 2 and len(self.history_data['x_9']) >= 2:
            c_prev = float(self.data_close[-1])
            c_curr = float(self.data_close[0])
            x9_prev = self.history_data['x_9'][-2]
            x9_curr = self.history_data['x_9'][-1]
            cross_c_x9 = self.tdx.CROSS_simple(c_prev, c_curr, x9_prev, x9_curr)
            newnumber_condition = newnumber_value < 9
            c_p3_condition = current_price > p3_value
            jichub_value = cross_c_x9 and newnumber_condition and c_p3_condition and c1_value
        
        # 基础BP:=REF(C,NEWNUMBER);
        jichubp_value = self.tdx.REF(self.data_close, newnumber_value)
        
        # 基础SP:=基础BP*1.05;
        jichusp_value = jichubp_value * 1.05
        
        # 基础S:= CROSS(DDD1,C)  OR  CROSS(H,基础SP) OR LL  OR CROSS(H,GD);
        jichus_value = False
        cross_ddd1_c = False
        cross_h_jichusp = False
        cross_h_gd = False
        
        # CROSS(DDD1,C)
        if len(self.data_close) >= 2:
            c_prev = float(self.data_close[-1])
            c_curr = float(self.data_close[0])
            cross_ddd1_c = self.tdx.CROSS_simple(ddd1_value, ddd1_value, c_prev, c_curr)
        
        # CROSS(H,基础SP)
        if len(self.data_high) >= 2:
            h_prev = float(self.data_high[-1])
            h_curr = float(self.data_high[0])
            cross_h_jichusp = self.tdx.CROSS_simple(h_prev, h_curr, jichusp_value, jichusp_value)
        
        # CROSS(H,GD)
        if len(self.data_high) >= 2:
            h_prev = float(self.data_high[-1])
            h_curr = float(self.data_high[0])
            cross_h_gd = self.tdx.CROSS_simple(h_prev, h_curr, gd_value, gd_value)
        
        jichus_value = cross_ddd1_c or cross_h_jichusp or ll_value or cross_h_gd
        
        # 记录每日参数到日志
        params_dict = {
            'date': current_date,
            'close': current_price,
            'low': current_low,
            'high': current_high,
            'x_13': bool(x_13_numeric),
            'x_14': x_14_value,
            'ddd1': ddd1_value,
            'newb': newb_value,
            'newnumber': newnumber_value,
            'p3': p3_value,
            'x_7': x_7_value,
            'x_8': x_8_value,
            'x_9': x_9_value,
            'hl': hl_value,
            'll': ll_value,
            'x_10': bool(x_10_numeric),
            'x_11': x_11_value,
            'gd': gd_value,
            'jichub': jichub_value,
            'jichus': jichus_value
        }
        
        self.log_daily_params(params_dict)
        
        # 记录信号到数据库（不需要实际买卖，只记录信号）
        # 买入信号：基础B信号
        if jichub_value:
            buy_info = f"CROSS(C,X_9)={cross_c_x9}, NEWNUMBER<9={newnumber_value<9}, C>P3={current_price>p3_value}, C1={c1_value}"
            self.save_signal_to_database('buy_signal', current_date, current_price, buy_info)
        
        # 卖出信号：基础S信号
        if jichus_value:
            sell_reasons = []
            if cross_ddd1_c:
                sell_reasons.append("CROSS(DDD1,C)")
            if cross_h_jichusp:
                sell_reasons.append("CROSS(H,基础SP)")
            if ll_value:
                sell_reasons.append("LL")
            if cross_h_gd:
                sell_reasons.append("CROSS(H,GD)")
            sell_info = f"卖出原因: {', '.join(sell_reasons)}"
            self.save_signal_to_database('sell_signal', current_date, current_price, sell_info)

    def stop(self):
        """策略结束时调用"""
        self.logger.info(f"策略运行结束 - 最终资产价值: {self.broker.getvalue():.2f}")
        print(f'=== TDXGPJY策略执行完成 ===')
        print(f'日志文件已保存到: tdx_gpjy_strategy_{self.stock_code}_*.log')

